home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / vol_100 / 154_01 / grep2.c < prev    next >
Text File  |  1980-01-01  |  11KB  |  443 lines

  1. /* grep.c: attempt to get UNIX pattern-matching on a micro */
  2.  
  3. /* From DECUS C Tools package on DEC systems - for non-commercial
  4.     use only.  Modifications by Chuck Allison, April 1985:
  5.  
  6.         - handles quoted args (for embedded spaces)
  7.         - expands wildcards against indicated directory
  8.         - distinguishes case (ignore with -i)
  9. */
  10.  
  11. #include <makearg.c>    /* ..includes <stdio.h>, <ctype.h>, <dos.h>.. */
  12.  
  13. #define LMAX    512
  14. #define PMAX    256
  15. #define MAXFILES 150
  16. #define CHAR    1
  17. #define BOL     2
  18. #define EOL     3
  19. #define ANY     4
  20. #define CLASS   5
  21. #define NCLASS  6
  22. #define STAR    7
  23. #define PLUS    8
  24. #define MINUS   9
  25. #define ALPHA   10
  26. #define DIGIT   11
  27. #define NALPHA  12
  28. #define WHITE   13
  29. #define RANGE   14
  30. #define ENDPAT  15
  31. #define TRUE    1
  32. #define FALSE   0
  33.  
  34. int  cflag = FALSE,
  35.         fflag = FALSE,
  36.      nflag = FALSE,
  37.      vflag = FALSE,
  38.      iflag = FALSE;
  39.  
  40. char    *pp,
  41.         lbuf[LMAX],
  42.         pbuf[PMAX];
  43.  
  44.  
  45. main()
  46. {
  47.    register char   *p;
  48.    register int    i;
  49.    FILE            *f;
  50.    char *xargv[MAXFILES];
  51.    int xargc, maxarg = MAXFILES;
  52.  
  53.    /* ..this must be first; processes args.. */
  54.    makeargv();
  55.  
  56.    if (argc <= 1)
  57.       usage("No arguments");
  58.  
  59.    for (; *(p = *(argv+1)) == '-'; ++argv, --argc)
  60.            while (*++p)
  61.             switch(tolower(*p))
  62.             {
  63.                 case 'c': 
  64.                     cflag = !cflag;
  65.                        break;
  66.                 case 'f':
  67.                     fflag = !fflag;
  68.                        break;
  69.                 case 'n':
  70.                     nflag = !nflag;
  71.                        break;
  72.                 case 'v':
  73.                     vflag = !vflag;
  74.                        break;
  75.                 case 'i':
  76.                     iflag = !iflag;
  77.                        break;
  78.                 default:    usage("Unknown flag");
  79.             }
  80.  
  81.    compile(*++argv);
  82.    --argc;
  83.  
  84.    if (argc == 1)
  85.       grep(stdin, 0);
  86.    else
  87.    {
  88.       /* ..expand file arguments.. (Mark Williams C only!).. */
  89.       xargc = exargs("",argc,argv,xargv,maxarg);
  90.  
  91.       /* ..check file switch.. */
  92.       if (xargc > 1)
  93.           fflag = !fflag;
  94.  
  95.       for (i = 0; i < xargc; ++i)
  96.             if ((f = fopen(xargv[i],"r")) != NULL)
  97.             {
  98.                 grep(f,xargv[i]);
  99.                 fclose(f);
  100.             }
  101.             else
  102.                 fprintf(stderr,"can't open %s\n",xargv[i]);
  103.    }
  104. }
  105.  
  106.  
  107. usage(s)
  108. char *s;
  109. {
  110.    fprintf(stderr, "?GREP-E-%s\n", s);
  111.    fprintf(stderr,
  112.       "Usage: grep [-cfnv] pattern [file ...] \n");
  113.    exit(1);
  114. }
  115.  
  116.  
  117. compile(source)
  118. char *source;
  119. /* ..Compile the pattern into global pbuf[].. */
  120. {
  121.    register char  *s;         /* Source string pointer     */
  122.    register char  *lp;        /* Last pattern pointer      */
  123.    register int   c;          /* Current character         */
  124.    int            o;          /* Temp                      */
  125.    char           *spp;       /* Save beginning of pattern */
  126.    char           *cclass();  /* Compile class routine     */
  127.  
  128.    s = source;
  129.    pp = pbuf;
  130.  
  131.    while (c = *s++)
  132.    {
  133.       /* ..STAR, PLUS and MINUS are special.. */
  134.       if (c == '*' || c == '+' || c == '-')
  135.       {
  136.          if ( pp == pbuf ||
  137.               (o=pp[-1]) == BOL ||
  138.               o == EOL ||
  139.               o == STAR ||
  140.               o == PLUS ||
  141.               o == MINUS
  142.             )
  143.             badpat("Illegal occurrance op.", source, s);
  144.          store(ENDPAT);
  145.          store(ENDPAT);
  146.          spp = pp;               /* Save pattern end     */
  147.          while (--pp > lp)       /* Move pattern down    */
  148.             *pp = pp[-1];        /* one byte             */
  149.          *pp =   (c == '*') ? STAR :
  150.             (c == '-') ? MINUS : PLUS;
  151.          pp = spp;               /* Restore pattern end  */
  152.          continue;
  153.       }
  154.  
  155.       /* ..All the rest.. */
  156.       lp = pp;         /* ..Remember start.. */
  157.       switch(c)
  158.       {
  159.           case '^':
  160.              store(BOL);
  161.              break;
  162.           case '$':
  163.              store(EOL);
  164.              break;
  165.           case '.':
  166.              store(ANY);
  167.              break;
  168.           case '[':
  169.              s = cclass(source, s);
  170.              break;
  171.           case ':':
  172.              if (*s)
  173.              {
  174.                 c = *s++;
  175.                 switch(tolower(c))
  176.                 {
  177.                     case 'a':
  178.                        store(ALPHA);
  179.                        break;
  180.                     case 'd':
  181.                        store(DIGIT);
  182.                        break;
  183.                     case 'n':
  184.                        store(NALPHA);
  185.                        break;
  186.                     case ' ':
  187.                        store(WHITE);
  188.                        break;
  189.                     default:
  190.                        badpat("Unknown : type", source, s);
  191.                 }
  192.                 break;
  193.              }
  194.              else
  195.                 badpat("No : type", source, s);
  196.          case '\\':
  197.             if (*s)
  198.             c = *s++;
  199.          default:
  200.             store(CHAR);
  201.             store(iflag ? tolower(c) : c);
  202.       }
  203.    }
  204.    store(ENDPAT);
  205.    store('\0');
  206. }
  207.  
  208.  
  209. char *cclass(source, src)
  210. char *source;    /* ..Pattern start.. */
  211. char *src;      /* ..Class start.. */
  212. /* ..Compile a class (within []).. */
  213. {
  214.    register char   *s;        /* Source pointer    */
  215.    register char   *cp;       /* Pattern start     */
  216.    register int    c;         /* Current character */
  217.    int             o;                 /* ..Temp.. */
  218.  
  219.    s = src;
  220.    o = CLASS;
  221.    if (*s == '^')
  222.    {
  223.       ++s;
  224.       o = NCLASS;
  225.    }
  226.    store(o);
  227.    cp = pp;
  228.    store(0);                         /* ..Byte count.. */
  229.  
  230.    while ((c = *s++) && c!=']')
  231.    {
  232.       if (c == '\\')
  233.       {  /* ..Store quoted char.. */
  234.          if ((c = *s++) == '\0')     /* ..Gotta get something.. */
  235.             badpat("Class terminates badly", source, s);
  236.          else
  237.              store(iflag ? tolower(c) : c);
  238.       }
  239.       else if (c == '-' && (pp - cp) > 1 && *s != ']' && *s != '\0')
  240.       {
  241.          c = pp[-1];             /* Range start     */
  242.          pp[-1] = RANGE;         /* Range signal    */
  243.          store(c);               /* Re-store start  */
  244.          c = *s++;               /* Get end char and*/
  245.          store(iflag ? tolower(c) : c);
  246.       }
  247.       else
  248.          store(iflag ? tolower(c) : c);
  249.    }
  250.  
  251.    if (c != ']')
  252.       badpat("Unterminated class", source, s);
  253.    if ((c = (pp - cp)) >= 256)
  254.       badpat("Class too large", source, s);
  255.    if (c == 0)
  256.       badpat("Empty class", source, s);
  257.    *cp = c;
  258.    return(s);
  259. }
  260.  
  261.  
  262. store(op)
  263. {
  264.    if (pp >= &pbuf[PMAX])
  265.       error("Pattern too complex\n");
  266.    *pp++ = op;
  267. }
  268.  
  269.  
  270. badpat(message, source)
  271. char  *message,       /* ..Error message.. */
  272.       *source;        /* ..Pattern start.. */
  273. {
  274.    fprintf(stderr, "-GREP-E-%s, pattern is\"%s\"\n", message, source);
  275.    exit(1);
  276. }
  277.  
  278.  
  279.  
  280. grep(fp, fn)
  281. FILE       *fp;       /* File to process            */
  282. char       *fn;       /* File name (for -f option)  */
  283. /* ..Scan the file for the pattern in pbuf[].. */
  284. {
  285.    register int lno, count, m;
  286.  
  287.    lno = 0;
  288.    count = 0;
  289.    while (fgets(lbuf, LMAX, fp))
  290.    {
  291.       ++lno;
  292.       m = match();
  293.       if ((m && !vflag) || (!m && vflag))
  294.       {
  295.          ++count;
  296.          if (!cflag)
  297.          {
  298.             if (fflag && fn) 
  299.             {
  300.                fprintf(stdout,"\n\nFile: %s\n\n",fn);
  301.                fn = 0;
  302.             }
  303.             if (nflag)
  304.                printf("%d\t", lno);
  305.             fputs(lbuf,stdout);
  306.          }
  307.       }
  308.    }
  309.    if (cflag)
  310.    {
  311.       if (fflag && fn)
  312.             fprintf(stdout,"\n\nFile: %s\n\n",fn);
  313.       printf("%d\n", count);
  314.    }
  315. }
  316.  
  317.  
  318. match()
  319. /* ..Match the current line (in lbuf[]), return 1 if it does.. */
  320. {
  321.    register char *l;        /* ..Line pointer.. */
  322.    char *pmatch();
  323.  
  324.    for (l = lbuf; *l; l++)
  325.       if (pmatch(l, pbuf))
  326.          return(1);
  327.  
  328.    return(0);
  329. }
  330.  
  331.  
  332. char *pmatch(line, pattern)
  333. char *line,     /* ..(partial) line to match.. */
  334.      *pattern;  /* ..(partial) pattern to match.. */
  335. {
  336.    register char   *l;        /* ..Current line pointer.. */
  337.    register char   *p;        /* ..Current pattern pointer.. */
  338.    register char   c;         /* ..Current character.. */
  339.    register char   d;         /* ..Temporary character.. */
  340.    char            *e;        /* ..End for STAR and PLUS match.. */
  341.    int             op;        /* ..Pattern operation.. */
  342.    int             n;         /* ..Class counter